<!DOCTYPE html>
<html>

<head>
    <title>Bootstrap5 实例</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.staticfile.net/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.staticfile.net/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
    <script src="static/three.min.js"></script>
    <style>
        .grid-container {
            display: grid;
            grid-template-columns: auto auto auto;
        }
    </style>
</head>

<body>
    <div class="grid-container">
        <div>
            <div id="first3d" style="display: none;margin:5px;"></div>
            <div id="second3d" style="display: none;margin:5px;"></div>
        </div>
        <div id="baseid" class="btn-group-vertical" style="margin: auto;">
            <div class="input-group">
                <button type="button" class="form-control btn btn-primary" onclick="gt.main(event)">New</button>
                <button type="button" class="form-control btn btn-primary" onclick="gt.main(event)">Show</button>
            </div>
            <div class="input-group">
                <span id="posColorList" class="badge bg-info" style="width: 35px;">0</span>
                <button type="button" class="btn btn-primary" onclick="gt.main(event)">-</button>
                <input class="form-control" type="range" id="myRange" onchange="gt.main(event)" value="0" min="0"
                    max="0" step="1">
                <button type="button" class="btn btn-primary" onclick="gt.main(event)">+</button>
                <button id="man-auto" type="button" class="btn btn-primary" onclick="gt.main(event)">＞</button>
            </div>
            <div class="input-group">
                <button type="button" class="form-control btn btn-primary" onclick="gt.main(event)">记录</button>
                <button id="qp-mode" type="button" class="form-control btn btn-primary"
                    onclick="gt.main(event)">下棋模式</button>
            </div>
            <div style="margin: auto;">
                <canvas id="myCanvas" style="border:1px solid gray;"></canvas>
                <div id="main3d" style="width:600px;height:600px;margin:auto;display:none;"></div>
            </div>
            <textarea class="form-control" id="sgftext"></textarea>
        </div>
        <div>
            <div id="third3d" style="display: none;margin:5px;"></div>
            <div id="fourth3d" style="display: none;margin:5px;"></div>
        </div>
    </div>
    <script>
        var health_alert = false;
        function health() {
            const now = new Date();
            const minutes = now.getMinutes();
            if (minutes === 0 || minutes === 30) {
                if (health_alert) {
                    alert("游戏健康忠告：请注意休息，合理安排游戏时间。");
                    health_alert = false;
                }
            } else {
                health_alert = true;
            }
        }
        class DrawQipan {
            constructor(canvasid, grid = 20) {
                this.grid = grid;
                this.gridHalf = grid / 2;
                this.qipanWidth = 20 * this.grid;
                this.canvas = document.getElementById(canvasid);
                this.canvas.width = this.qipanWidth;
                this.canvas.height = this.qipanWidth;
                this.ctx = this.create_ctx(this.canvas);
                this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
                this.painting = false;
                this.blueList = ["rg", "oc"];
                this.selectedList = [];
                this.qipanList = [];
                this.setupClickListener(this.canvas, this);
                this.isShowText = true;
                this.strokeStyle = "B";
                this.draw({});
            }
            create_ctx(canvas) {
                let ctx = canvas.getContext("2d");
                ctx.strokeStyle = "black";
                ctx.lineWidth = 2;
                return ctx;
            }
            setupClickListener(element, someVariable) {
                element.addEventListener('mousedown', function (event) {
                    someVariable.painting = true;
                    someVariable.canvasListener("mousedown", event.clientX, event.clientY);
                });
                element.addEventListener('mousemove', function (event) {
                    if (someVariable.painting) {
                        someVariable.canvasListener("mousemove", event.clientX, event.clientY);
                    }
                });
                element.addEventListener('mouseup', function (event) {
                    if (someVariable.painting) {
                        someVariable.painting = false;
                        someVariable.canvasListener("mouseup", event.clientX, event.clientY);
                    }
                });
            }
            canvasListener(action, x, y) {
                let qpMode = document.getElementById("qp-mode").innerText;
                let rect, rx, ry, gr, gc, position;
                rect = this.canvas.getBoundingClientRect();
                position = this.coordinate_position(x, y);
                [rx, ry] = this.position_coordinate(position);
                if (qpMode == "下棋模式" && action == "mousedown") {
                    let sgf = this.strokeStyle + "[" + position + "]";
                } else if (qpMode == "选择模式" && action == "mousedown") {
                    this.startPosition = position;
                    this.painting = true;
                    this.selectList = [position];
                    this.ctx.strokeStyle = "red";
                    this.ctx.lineWidth = 2;
                    this.ctx.beginPath();
                    this.ctx.moveTo(rx, ry);
                } else if (qpMode == "选择模式" && action == "mousemove") {
                    if (this.painting) {
                        if (position != this.selectList[this.selectList.length - 1]) {
                            this.selectList.push(position);
                            this.ctx.lineTo(rx, ry);
                            this.ctx.stroke();
                        }
                    }
                } else if (qpMode == "选择模式" && action == "mouseup") {
                    this.painting = false;
                    if (this.selectList.length > 0) {
                        this.selectedList.push(JSON.parse(JSON.stringify(this.selectList)));
                    }
                    let [sgf, pcDict, pcList, blueList] = this.select(this.selectList);
                    this.qipanList.push(JSON.parse(JSON.stringify([sgf, pcDict, pcList, blueList])));
                }
            }
            select(selectedList) {
                if (selectedList[0] != selectedList[selectedList.length - 1]) {
                    selectedList.push(selectedList[0]);
                }
                let linshiList = [], blueList = [];
                sgo.sgf.forEach((item, index) => {
                    if (this.isPointInPolygon(item.slice(2, 4), selectedList)) {
                        linshiList.push(item.slice(2, 4));
                    }
                });
                selectedList.concat(linshiList).forEach((item, index) => {
                    blueList.includes(item) || blueList.push(item);
                });
                let sgf = [], pcDict = {}, pcList = [];
                sgo.sgf.forEach((item, index) => {
                    if (blueList.includes(item.slice(2, 4))) {
                        sgf.push(item);
                        pcList.push(JSON.parse(JSON.stringify(sgo.posColorList[index])));
                    }
                });
                pcDict = JSON.parse(JSON.stringify(pcList.at(-1)));
                return [sgf, pcDict, pcList, blueList];
            }
            draw(posColor) {
                let cx, cy, current;
                let start = this.grid;
                let end = 19 * this.grid;
                let radius = Math.floor(this.grid / 3 - 1);
                this.ctx.clearRect(0, 0, this.qipanWidth, this.qipanWidth);
                this.ctx.fillStyle = "GoldenRod";
                this.ctx.fillRect(0, 0, this.qipanWidth, this.qipanWidth);
                this.ctx.lineWidth = 2;
                this.ctx.strokeStyle = "black";
                this.ctx.beginPath();
                this.positions.forEach((row, ri) => {
                    current = (this.positions.indexOf(row) + 1) * this.grid;
                    this.ctx.moveTo(current, start);
                    this.ctx.lineTo(current, end);
                    this.ctx.moveTo(start, current);
                    this.ctx.lineTo(end, current);
                });
                let pos = ["d", "j", "p"];
                for (let row in pos) {
                    for (let col in pos) {
                        [cx, cy] = this.position_coordinate(pos[row] + pos[col]);
                        this.ctx.moveTo(cx + radius, cy);
                        this.ctx.arc(cx, cy, radius, 0, 2 * Math.PI);
                    }
                }
                this.ctx.stroke();
                let strokeStyle = { B: "black", W: "White" };
                for (let pos in posColor) {
                    this.ctx.beginPath();
                    [cx, cy] = this.position_coordinate(pos);
                    this.ctx.moveTo(cx + Math.floor(this.grid / 2 - 1), cy);
                    this.ctx.lineWidth = 3;
                    if (pos == sgo.sgf[Number(document.getElementById("myRange").value)].slice(2, 4)) {
                        this.ctx.strokeStyle = "Gold";
                    } else if (this.blueList.includes(pos)) {
                        this.ctx.strokeStyle = "LightBlue";
                    } else {
                        this.ctx.strokeStyle = "Gray";
                        if (this.blueList.length > 0) {
                            this.ctx.globalAlpha = 0.5;
                        }
                    }
                    this.ctx.arc(cx, cy, Math.floor(this.grid / 2 - 1), 0, 2 * Math.PI);
                    this.ctx.fillStyle = strokeStyle[posColor[pos][0]];
                    this.ctx.fill();
                    this.ctx.globalAlpha = 1.0;
                    if (this.isShowText) {
                        if (posColor[pos][0] == "B") {
                            this.ctx.fillStyle = "White";
                        } else {
                            this.ctx.fillStyle = "black";
                        }
                        this.ctx.textBaseline = "middle";
                        this.ctx.fillText(posColor[pos][1], cx - this.ctx.measureText(posColor[pos][1]).width / 2, cy);
                    }
                    this.ctx.stroke();
                }
                //this.ctx.strokeStyle = "black";
                this.base64Image = this.canvas.toDataURL('image/png');
            }
            coordinate_position(x, y) {
                let rect, row, col;
                rect = this.canvas.getBoundingClientRect();
                row = this.minmax(Math.floor((x + this.grid / 2 - rect.left) / this.grid) - 1);
                col = this.minmax(Math.floor((y + this.grid / 2 - rect.top) / this.grid) - 1);
                return this.positions[row] + this.positions[col];
            }
            minmax(coordinate) {
                return Math.min(18, Math.max(0, coordinate));
            }
            position_coordinate(position) {
                let row, col, rect, rx, cy;
                rect = this.canvas.getBoundingClientRect();
                row = this.positions.indexOf(position.slice(0, 1));
                col = this.positions.indexOf(position.slice(1, 2));
                rx = Math.floor((row + 1) * this.grid);
                cy = Math.floor((col + 1) * this.grid);
                return [rx, cy];
            }
            canvas_size(qp_row, qp_col) {
                document.getElementById("myCanvas").width = this.qipanWidth;
                document.getElementById("myCanvas").height = this.qipanWidth;
            }
            isPointInPolygon(point, polygon) {
                let numIntersections = 0;
                let [x, y] = this.position_coordinate(point);
                const n = polygon.length;
                for (let i = 0, j = n - 1; i < n; j = i++) {
                    let [xi, yi] = this.position_coordinate(polygon[i]);
                    let [xj, yj] = this.position_coordinate(polygon[j]);
                    if ((yi > y) != (yj > y) &&
                        x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
                        numIntersections++;
                    }
                }
                return numIntersections % 2 !== 0;
            }
        }
        const drawQipan = new DrawQipan("myCanvas", 30);

        class simpleGo {
            constructor() {
                this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
                this.newWeiQi([], {}, []);
                this.goString = { string: [], empty: [] };
            }
            go_handler(item = "B[qd]") {
                var position = item.slice(2, 4);
                if (this.posColor.hasOwnProperty(position)) {
                    return false;
                } else {
                    this.posColor[position] = [item[0]];
                }
                var del_pos = [];
                var near_pos = this.near_positions(position);
                for (var npn in near_pos) {
                    if (this.posColor.hasOwnProperty(near_pos[npn])) {
                        if (this.posColor[near_pos[npn]][0] != this.posColor[position][0]) {
                            this.goString = { 'string': [], 'empty': [] };
                            this.go_string(near_pos[npn]);
                            if (this.goString['empty'].length == 0) {
                                for (var spn in this.goString['string']) {
                                    del_pos.includes(this.goString['string'][spn]) || del_pos.push(this.goString['string'][spn]);
                                }
                            }
                        }
                    }
                }
                if (del_pos.length == 0) {
                    this.goString = { 'string': [], 'empty': [] };
                    this.go_string(position);
                    if (this.goString['empty'].length == 0) {
                        delete this.posColor[position];
                        return false;
                    }
                } else {
                    for (var d_p in del_pos) {
                        delete this.posColor[del_pos[d_p]];
                    }
                }
                this.sgf.push(item);
                this.posColor[position].push(this.sgf.length)
                this.posColorList.push(JSON.parse(JSON.stringify(this.posColor)));
                return true;
            }
            go_string(position) {
                this.goString['string'].push(position);
                var nPos = this.near_positions(position);
                for (var np in nPos) {
                    if (this.posColor.hasOwnProperty(nPos[np])) {
                        if (!this.goString['string'].includes(nPos[np]) && this.posColor[nPos[np]][0] == this.posColor[position][0]) {
                            this.go_string(nPos[np]);
                        }
                    } else {
                        this.goString['empty'].includes(nPos[np]) || this.goString['empty'].push(nPos[np]);
                    }
                }
            }
            near_positions(position) {
                var near_pos = [];
                var row = this.near(position[0]);
                var col = this.near(position[1]);
                for (var r in row) {
                    near_pos.push(row[r] + position[1]);
                }
                for (var c in col) {
                    near_pos.push(position[0] + col[c]);
                }
                return near_pos;
            }
            near(char) {
                switch (char) {
                    case "a":
                        return ["b"];
                    case "s":
                        return ["r"];
                    case "b": case "c": case "d": case "e": case "f": case "g":
                    case "h": case "i": case "j": case "k": case "l": case "m":
                    case "n": case "o": case "p": case "q": case "r":
                    default:
                        var pos = this.positions.indexOf(char);
                        return [this.positions[pos - 1], this.positions[pos + 1]];
                }
            }
            newWeiQi(sgf, posColor, posColorList) {
                this.sgf = sgf;
                this.posColor = posColor;
                this.posColorList = posColorList;
            }
        }
        const sgo = new simpleGo();
        class ThreeGo {
            constructor() {
                let width = 600, height = 600;
                this.scene = this.create_scene();
                this.camera = this.create_camera(width, height);
                this.renderer = this.create_renderer(width, height);
                document.getElementById("main3d").innerHTML = "";
                document.getElementById("main3d").appendChild(this.renderer.domElement);
                this.face = this.create_face([0, 3, 0]);
                this.face.rotation.x = -Math.PI / 2;
                this.scene.add(this.face);
                //this.scene.add(new THREE.AxesHelper(5));
            }
            create_scene() {
                return new THREE.Scene();
            }
            create_camera(width = 600, height = 600) {
                let camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
                camera.position.set(5, 9, 5);
                camera.lookAt(new THREE.Vector3(0, 0, 0));
                return camera;
            }
            create_renderer(width = 600, height = 600) {
                let renderer = new THREE.WebGLRenderer();
                renderer.setSize(width, height);
                renderer.setClearColor(new THREE.Color('skyblue'));
                return renderer;
            }
            create_material(imgeData) {
                let textureLoader = new THREE.TextureLoader();
                let texture = textureLoader.load(imgeData);
                let material = new THREE.MeshBasicMaterial({ map: texture });
                return material;
            }
            create_face(position = [0, 0, 0]) {
                let geometry = new THREE.PlaneGeometry(10, 10);
                let material = this.create_material(drawQipan.base64Image);
                let mesh = new THREE.Mesh(geometry, material);
                mesh.position.set(position[0], position[1], position[2]);
                return mesh;
            }
        }
        let tg = new ThreeGo();
        class MyThree {
            constructor(canvasid, width = 636, height = 380) {
                this.width = width;
                this.height = height;
                document.getElementById(canvasid).width = width;
                document.getElementById(canvasid).height = height;
                this.scene = this.create_scene();
                this.camera = this.create_camera();
                this.renderer = this.create_renderer();
                this.face = this.create_face(drawQipan.base64Image);
                this.face.rotation.x = -Math.PI / 2;
                this.scene.add(this.face);
            }
            create_scene() {
                return new THREE.Scene();
            }
            create_camera(position = [4, 7, 4]) {
                let camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
                camera.position.set(position[0], position[1], position[0]);
                camera.lookAt(new THREE.Vector3(0, 0, 0));
                return camera;
            }
            create_renderer() {
                let renderer = new THREE.WebGLRenderer();
                renderer.setSize(this.width, this.height);
                renderer.setClearColor(new THREE.Color('skyblue'));
                return renderer;
            }
            create_material(imgeData) {
                let textureLoader = new THREE.TextureLoader();
                let texture = textureLoader.load(imgeData);
                let material = new THREE.MeshBasicMaterial({ map: texture });
                return material;
            }
            create_face(imgeData, position = [0, 3, 0]) {
                let geometry = new THREE.PlaneGeometry(10, 10);
                let material = this.create_material(imgeData);
                let mesh = new THREE.Mesh(geometry, material);
                mesh.position.set(position[0], position[1], position[2]);
                return mesh;
            }
        }
        class Tools {
            constructor() {
                this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
                this.combinedPattern = /[\u4e00-\u9fa5a-zA-Z0-9;\[\]\-： ]+/g;
                this.sgf = [];
                this.blueList = [];
                this.goldDict = {};
                this.autoRun = false;
            }
            main(event) {
                switch (event.target.textContent) {
                    case "New":
                        sgo.newWeiQi([], {}, []);
                        drawQipan.draw({});
                        break;
                    case "Show":
                        drawQipan.blueList = [];
                        sgo.newWeiQi([], {}, []);
                        if (document.getElementById("sgftext").value == "") {
                            egm.handle(sgftext)
                        } else {
                            egm.handle(document.getElementById("sgftext").value)
                        }
                        document.getElementById("myRange").max = sgo.sgf.length - 1;
                        document.getElementById("myRange").value = sgo.sgf.length - 1;
                        document.getElementById("posColorList").textContent = Number(document.getElementById("myRange").value) + 1;
                        drawQipan.qipanList = [JSON.parse(JSON.stringify([sgo.sgf, sgo.posColor, sgo.posColorList, []]))];
                        drawQipan.draw(sgo.posColor);
                        break;
                    case "-":
                        document.getElementById("myRange").value = Math.max(0, Number(document.getElementById("myRange").value) - 1);
                        drawQipan.draw(sgo.posColorList[Number(document.getElementById("myRange").value)]);
                        break;
                    case "+":
                        document.getElementById("myRange").value = Math.min(sgo.sgf.length - 1, Number(document.getElementById("myRange").value) + 1);
                        drawQipan.draw(sgo.posColorList[Number(document.getElementById("myRange").value)]);
                        break;
                    case "＞":
                        let [sgf, pcDict, pcList, blueList] = drawQipan.qipanList.at(-1);
                        sgo.newWeiQi(sgf, pcDict, pcList);
                        drawQipan.blueList = blueList;
                        document.getElementById("myRange").max = sgo.sgf.length - 1;
                        document.getElementById("myRange").value = 0;
                        document.getElementById('myCanvas').style.display = "none";
                        this.renderer({ "main3d": tg })
                        if (!this.autoRun) { this.autoRun = true; }
                        break;
                    case "记录":
                        break;
                    case "步数":
                        drawQipan.isShowText ? drawQipan.isShowText = false : drawQipan.isShowText = true;
                        break;
                    case "下棋模式":
                        drawQipan.selectedList = [];
                        event.target.textContent = "选择模式";
                        break;
                    case "选择模式":
                        event.target.textContent = "下棋模式";
                        break;
                    default:
                        drawQipan.draw(sgo.posColorList[Number(document.getElementById("myRange").value)]);
                        break;
                }
            }
            autorunning() {
                if (document.getElementById("myRange").value < sgo.posColorList.length - 1) {
                    drawQipan.draw(sgo.posColorList[document.getElementById("myRange").value]);
                    document.getElementById("posColorList").textContent = document.getElementById("myRange").value++;
                } else {
                    this.autoRun = false;
                    this.display(["main3d"], "none");
                    document.getElementById('myCanvas').style.display = "block";
                }
            }
            display(idList, display) {
                for (let index in idList) {
                    if (display == "none") {
                        document.getElementById(idList[index]).style.display = "none";
                    } else if (display == "block") {
                        document.getElementById(idList[index]).style.display = "block";
                    }
                    document.getElementById(idList[index]).innerHTML = "";
                }
            }
            renderer(dict3d) {
                for (let key in dict3d) {
                    document.getElementById(key).innerHTML = "";
                    document.getElementById(key).appendChild(dict3d[key].renderer.domElement);
                    document.getElementById(key).style.display = "block";
                }
            }
        }
        const gt = new Tools();
        const sgftext = `(;CA[UTF-8]AP[YuanYu]GM[1]FF[4]
SZ[19]
GN[2018腾讯世界人工智能围棋大赛决赛第1局 30日10：00]
DT[2018-07-30]
PB[Golaxy]BR[9d]
PW[FineArt]WR[9d]
KM[7.5]HA[0]RU[Chinese]RE[W+R]TM[3600]TC[10]TT[60]
;B[qd];W[pp];B[dd];W[dp];B[qn];W[qo];B[pn];W[np];B[pj];W[od];B[lc]
;W[me];B[lq];W[qe];B[fq];W[cc];B[qq];W[rn];B[cd];W[dc];B[ed];W[ec]
;B[rm];W[or];B[ro];W[rp];B[qp];W[po];B[sn];W[rq];B[fc];W[fb];B[cn]
;W[er];B[bc];W[bb];B[eb];W[db];B[gb];W[pd];B[eo];W[co];B[bn];W[fp]
;B[ep];W[eq];B[do];W[cq];B[fr];W[iq];B[hp];W[gq];B[gp];W[fo];B[fn]
;W[go];B[hn];W[gr];B[gn];W[fs];B[ei];W[bd];B[be];W[ac];B[cf];W[ih]
;B[qc];W[rf];B[pf];W[qh];B[ob];W[nb];B[oc];W[pc];B[pb];W[rd];B[nd]
;W[qb];B[oe];W[rc];B[nc];W[if];B[hg];W[ig];B[je];W[gi];B[fg];W[hf]
;B[fj];W[lg];B[lf];W[mg];B[kg];W[kh];B[mf];W[ff];B[gg];W[fd];B[gc]
;W[hd];B[fe];W[gd];B[ic];W[gj];B[kf];W[bg];B[cg];W[kj];B[bo];W[gk]
;B[fk];W[id];B[jc];W[eh];B[fh];W[fi];B[ej];W[fl];B[el];W[gl];B[lo]
;W[ae];B[bh];W[em];B[dl];W[km];B[ho];W[qk];B[ol];W[bf];B[ce];W[gf]
;B[ef];W[qj];B[hq];W[hr];B[pi];W[qi];B[lk];W[kk];B[lh];W[li];B[mh]
;W[ng];B[oo];W[pq];B[og];W[nh];B[mi];W[oh];B[qr];W[rr];B[mj];W[ph]
;B[lm];W[kl];B[jh];W[ki];B[bq];W[hh];B[eg];W[ll];B[ml];W[no];B[ln]
;W[nk];B[mk];W[nm];B[nn];W[mm];B[nl];W[mn];B[om];W[mo];B[jq];W[rl]
;B[ql];W[pl];B[qm];W[ir];B[jn];W[pk];B[rk];W[on];B[pm];W[rj];B[sl]
;W[cr];B[jg];W[ji];B[hl];W[il];B[hm];W[jp];B[kp];W[kn];B[ko];W[ik]
;B[cp];W[jr];B[jo];W[hc];B[hb];W[ea];B[af];W[ag];B[fq];W[br];B[ar]
;W[lr];B[mr];W[kq];B[mq];W[ad];B[ah];W[af];B[fm];W[sp];B[nn];W[op]
;B[dq];W[dr];B[jm];W[jl];B[ls];W[on];B[kr];W[nf];B[ne];W[ok];B[hk]
;W[hj];B[pg];W[jd])`
        class extract_go_manual {
            constructor() {
                this.positions = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s"];
                this.combinedPattern = /[\u4e00-\u9fa5a-zA-Z0-9;\[\]\-： ]+/g;
            }
            handle(text) {
                sgo.newWeiQi([], {}, []);
                var results = text.match(this.combinedPattern) || [];
                var format_content = results.join('').split(";");
                for (var index in format_content) {
                    var item = format_content[index];
                    if (item.length == 5 && this.positions.includes(item[2]) && this.positions.includes(item[3])) {
                        sgo.go_handler(item);
                    }
                }
            }
        }
        const egm = new extract_go_manual();
        let start, ok;
        function animate(timestamp) {
            if (!start) start = timestamp;
            const progress = timestamp - start;
            if (gt.autoRun) {
                tg.face.rotation.z += 0.002;
                tg.renderer.render(tg.scene, tg.camera);
                if (ok && progress % 1000 < 30) {
                    ok = false;
                    gt.autorunning();
                    let textureLoader = new THREE.TextureLoader();
                    textureLoader.load(drawQipan.base64Image, function (texture) {
                        tg.face.material.map = texture;
                        tg.face.material.needsUpdate = true;
                    });
                    health();
                } else {
                    ok = true;
                }
            }
            requestAnimationFrame(animate);
        }
        requestAnimationFrame(animate);
    </script>
</body>

</html>